home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / FaxRecv.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  11KB  |  354 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/FaxRecv.c++,v 1.63 1994/04/04 18:24:29 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <unistd.h>
  26. #include <osfcn.h>
  27. #include <sys/stat.h>
  28. #include <sys/file.h>
  29. #include <ctype.h>
  30. #include <stdio.h>
  31.  
  32. #include <Dispatch/dispatcher.h>
  33.  
  34. #include "tiffio.h"
  35. #include "FaxServer.h"
  36. #include "FaxRecvInfo.h"
  37. #include "RegExArray.h"
  38. #include "faxServerApp.h"
  39. #include "t.30.h"
  40. #include "config.h"
  41.  
  42. /*
  43.  * FAX Server Reception Protocol.
  44.  */
  45.  
  46. fxBool
  47. FaxServer::recvFax()
  48. {
  49.     fxStr emsg;
  50.     changeState(RECEIVING);
  51.     traceStatus(FAXTRACE_PROTOCOL, "RECV: begin");
  52.     okToRecv = (qualifyTSI == "");    // anything ok if not qualifying
  53.     recvTSI = "";            // sender's identity initially unknown
  54.     FaxRecvInfoArray docs;
  55.     FaxRecvInfo info;
  56.     fxBool faxRecognized = FALSE;
  57.  
  58.     /*
  59.      * Create the first file ahead of time to avoid timing
  60.      * problems with Class 1 modems.  (Creating the file
  61.      * after recvBegin can cause part of the first page to
  62.      * be lost.)
  63.      */
  64.     TIFF* tif = setupForRecv("RECV", info, docs);
  65.     if (tif) {
  66.     recvStart = time(0);        // count initial negotiation
  67.     if (faxRecognized = modem->recvBegin(emsg)) {
  68.         (void) recvDocuments("RECV", tif, info, docs, emsg);
  69.         if (!modem->recvEnd(emsg))
  70.         traceStatus(FAXTRACE_PROTOCOL, "RECV: %s (end)", (char*) emsg);
  71.     } else {
  72.         traceStatus(FAXTRACE_PROTOCOL, "RECV: %s (begin)", (char*) emsg);
  73.         TIFFClose(tif);
  74.     }
  75.     }
  76.     /*
  77.      * Now that the session is completed, do local processing
  78.      * that might otherwise slow down the protocol (and potentially
  79.      * cause timing problems).
  80.      */
  81.     for (u_int i = 0, n = docs.length(); i < n; i++) {
  82.     const FaxRecvInfo& ri = docs[i];
  83.     if (ri.npages > 0) {
  84.         (void) chmod((char*) ri.qfile, recvFileMode);
  85.         app->notifyRecvDone(ri);
  86.     } else {
  87.         traceStatus(FAXTRACE_SERVER, "RECV: empty file \"%s\" deleted",
  88.         (char*) ri.qfile);
  89.         unlink((char*) ri.qfile);
  90.     }
  91.     }
  92.     traceStatus(FAXTRACE_PROTOCOL, "RECV: end");
  93.     return (faxRecognized);
  94. }
  95.  
  96. /*
  97.  * Create and lock a temp file for receiving data.
  98.  */
  99. TIFF*
  100. FaxServer::setupForRecv(const char* op, FaxRecvInfo& ri, FaxRecvInfoArray& docs)
  101. {
  102.     char* cp = tempnam(FAX_RECVDIR, "fax");
  103.     if (cp) {
  104.     ri.qfile = cp;
  105.     free(cp);
  106.     ri.npages = 0;            // mark it to be deleted...
  107.     docs.append(ri);        // ...add it in to the set
  108.     TIFF* tif = TIFFOpen(ri.qfile, "w");
  109.     if (tif != NULL) {
  110.         (void) flock(TIFFFileno(tif), LOCK_EX|LOCK_NB);
  111.         return (tif);
  112.     }
  113.     traceStatus(FAXTRACE_SERVER,
  114.         "%s: Unable to create file \"%s\" for received data", op,
  115.         (char*) ri.qfile);
  116.     } else
  117.     traceStatus(FAXTRACE_SERVER,
  118.         "%s: Unable to create temp file for received data", op);
  119.     return (NULL);
  120. }
  121.  
  122. /*
  123.  * Receive one or more documents.
  124.  */
  125. fxBool
  126. FaxServer::recvDocuments(const char* op, TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, fxStr& emsg)
  127. {
  128.     fxBool recvOK;
  129.     int ppm;
  130.     for (;;) {
  131.      if (!okToRecv) {
  132.         traceStatus(FAXTRACE_SERVER,
  133.         "%s: Permission denied (unacceptable client TSI)", op);
  134.         TIFFClose(tif);
  135.         return (FALSE);
  136.     }
  137.     traceStatus(FAXTRACE_SERVER, "RECV data in \"%s\"", (char*) info.qfile);
  138.     npages = 0;
  139.     time_t recvStart = time(0);
  140.     recvOK = recvFaxPhaseB(tif, ppm, emsg);
  141.     if (!recvOK)
  142.         traceStatus(FAXTRACE_PROTOCOL, "%s: %s (Phase B)", op, (char*)emsg);
  143.     TIFFClose(tif);
  144.     recvComplete(info, time(0) - recvStart, emsg);
  145.     docs[docs.length()-1] = info;
  146.     if (!recvOK || ppm == PPM_EOP)
  147.         return (recvOK);
  148.     /*
  149.      * Setup state for another file.
  150.      */
  151.     tif = setupForRecv(op, info, docs);
  152.     if (tif == NULL)
  153.         return (FALSE);
  154.     recvStart = time(0);
  155.     }
  156.     /*NOTREACHED*/
  157. }
  158.  
  159. /*
  160.  * Receive Phase B protocol processing.
  161.  */
  162. fxBool
  163. FaxServer::recvFaxPhaseB(TIFF* tif, int& ppm, fxStr& emsg)
  164. {
  165.     ppm = PPM_EOP;
  166.     do {
  167.     if (!modem->recvPage(tif, ppm, emsg))
  168.         return (FALSE);
  169.     // XXX handle PRI
  170.     if (PPM_PRI_MPS <= ppm && ppm <= PPM_PRI_EOP)
  171.         traceStatus(FAXTRACE_PROTOCOL, "RECV interrupt request ignored");
  172.     } while (ppm == PPM_MPS || ppm == PPM_PRI_MPS);
  173.     return (TRUE);
  174. }
  175.  
  176. /*
  177.  * Fill in a receive information block
  178.  * from the server's current receive state.
  179.  */
  180. void
  181. FaxServer::recvComplete(FaxRecvInfo& info, time_t recvTime, const fxStr& emsg)
  182. {
  183.     info.time = recvTime;
  184.     info.npages = npages;
  185.     info.pagewidth = pageWidthCodes[clientParams.wd];
  186.     info.pagelength = pageLengthCodes[clientParams.ln];
  187.     info.sigrate = atoi(Class2Params::bitRateNames[clientParams.br]);
  188.     info.protocol = Class2Params::dataFormatNames[clientParams.df];
  189.     info.resolution = (clientParams.vr == VR_FINE ? 196. : 98.);
  190.     info.sender = recvTSI;
  191.     info.reason = emsg;
  192. }
  193.  
  194. /*
  195.  * Process a received DCS.
  196.  */
  197. void
  198. FaxServer::recvDCS(const Class2Params& params)
  199. {
  200.     clientParams = params;
  201.  
  202.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE wants %s",
  203.     Class2Params::bitRateNames[params.br]);
  204.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE wants %s",
  205.     Class2Params::pageWidthNames[params.wd]);
  206.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE wants %s",
  207.     Class2Params::pageLengthNames[params.ln]);
  208.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE wants %s",
  209.     Class2Params::vresNames[params.vr]);
  210.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE wants %s",
  211.     Class2Params::dataFormatNames[params.df]);
  212. }
  213.  
  214. /*
  215.  * Process a received Non-Standard-Facilities message.
  216.  */
  217. void
  218. FaxServer::recvNSF(u_int)
  219. {
  220. }
  221.  
  222. /*
  223.  * Check a received TSI against any list of acceptable
  224.  * TSI patterns defined for the server.  This form of
  225.  * access control depends on the sender passing a valid
  226.  * TSI.  With caller-ID, this access control can be made
  227.  * more reliable.
  228.  */
  229. fxBool
  230. FaxServer::recvCheckTSI(const fxStr& tsi)
  231. {
  232.     recvTSI = tsi;
  233.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE TSI \"%s\"", (char*) tsi);
  234.     updateTSIPatterns();
  235.     if (qualifyTSI != "") {    // check against database of acceptable tsi's
  236.     okToRecv = FALSE;    // reject if no patterns!
  237.     if (tsiPats) {
  238.         for (u_int i = 0; i < tsiPats->length(); i++) {
  239.         RegEx* pat = (*tsiPats)[i];
  240.         if (pat->Search(tsi, tsi.length(), 0, tsi.length()) >= 0) {
  241.             okToRecv = TRUE;
  242.             break;
  243.         }
  244.         }
  245.     }
  246.     } else
  247.     okToRecv = TRUE;
  248.     traceStatus(FAXTRACE_SERVER, "%s TSI \"%s\"",
  249.     okToRecv ? "ACCEPT" : "REJECT", (char*) tsi);
  250.     if (okToRecv)
  251.     setServerStatus("Receiving from \"%s\"", (char*) tsi);
  252.     return (okToRecv);
  253. }
  254.  
  255. /*
  256.  * Prepare for the reception of page data by setting the
  257.  * TIFF tags to reflect the data characteristics.
  258.  */
  259. void
  260. FaxServer::recvSetupPage(TIFF* tif, long group3opts, int fillOrder)
  261. {
  262.     TIFFSetField(tif, TIFFTAG_SUBFILETYPE,    FILETYPE_PAGE);
  263.     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,
  264.     (u_long) pageWidthCodes[clientParams.wd]);
  265.     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,    1);
  266.     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,    PHOTOMETRIC_MINISWHITE);
  267.     TIFFSetField(tif, TIFFTAG_ORIENTATION,    ORIENTATION_TOPLEFT);
  268.     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL,    1);
  269.     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,    -1L);
  270.     TIFFSetField(tif, TIFFTAG_PLANARCONFIG,    PLANARCONFIG_CONTIG);
  271.     TIFFSetField(tif, TIFFTAG_FILLORDER,    fillOrder);
  272.     TIFFSetField(tif, TIFFTAG_XRESOLUTION,    204.);
  273.     TIFFSetField(tif, TIFFTAG_YRESOLUTION,
  274.     (clientParams.vr == VR_FINE) ? 196. : 98.);
  275.     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT,    RESUNIT_INCH);
  276.     TIFFSetField(tif, TIFFTAG_SOFTWARE,        "FlexFAX Version 2.2");
  277.     TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION,    (char*) recvTSI);
  278.     switch (clientParams.df) {
  279.     case DF_2DMMR:
  280.     TIFFSetField(tif, TIFFTAG_COMPRESSION,    COMPRESSION_CCITTFAX4);
  281.     break;
  282.     case DF_2DMRUNCOMP:
  283.     TIFFSetField(tif, TIFFTAG_COMPRESSION,    COMPRESSION_CCITTFAX3);
  284.     group3opts |= GROUP3OPT_2DENCODING|GROUP3OPT_UNCOMPRESSED;
  285.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,group3opts);
  286.     break;
  287.     case DF_2DMR:
  288.     TIFFSetField(tif, TIFFTAG_COMPRESSION,    COMPRESSION_CCITTFAX3);
  289.     group3opts |= GROUP3OPT_2DENCODING;
  290.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,group3opts);
  291.     break;
  292.     case DF_1DMR:
  293.     TIFFSetField(tif, TIFFTAG_COMPRESSION,    COMPRESSION_CCITTFAX3);
  294.     group3opts &= ~GROUP3OPT_2DENCODING;
  295.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,group3opts);
  296.     break;
  297.     }
  298.     char dateTime[24];
  299.     time_t now = time(0);
  300.     strftime(dateTime, sizeof (dateTime), "%Y:%m:%d %H:%M:%S", localtime(&now));
  301.     TIFFSetField(tif, TIFFTAG_DATETIME,        dateTime);
  302.     TIFFSetField(tif, TIFFTAG_MAKE,        (char*) modem->getManufacturer());
  303.     TIFFSetField(tif, TIFFTAG_MODEL,        (char*) modem->getModel());
  304.     TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, (char*) hostname);
  305. }
  306.  
  307. /*
  308.  * Update the TSI pattern array if the file
  309.  * of TSI patterns has been changed since the last
  310.  * time we read it.
  311.  */
  312. void
  313. FaxServer::updateTSIPatterns()
  314. {
  315.     FILE* fd = fopen((char*) qualifyTSI, "r");
  316.     if (fd != NULL) {
  317.     struct stat sb;
  318.     if (fstat(fileno(fd), &sb) >= 0 && sb.st_mtime >= lastPatModTime) {
  319.         RegExArray* pats = readTSIPatterns(fd);
  320.         if (tsiPats)
  321.         delete tsiPats;
  322.         tsiPats = pats;
  323.         lastPatModTime = sb.st_mtime;
  324.     }
  325.     fclose(fd);
  326.     } else if (tsiPats)
  327.     // file's been removed, delete any existing info
  328.     delete tsiPats, tsiPats = 0;
  329. }
  330.  
  331. /*
  332.  * Read the file of TSI patterns into an array.
  333.  */
  334. RegExArray*
  335. FaxServer::readTSIPatterns(FILE* fd)
  336. {
  337.     RegExArray* pats = new RegExArray;
  338.     char line[256];
  339.  
  340.     while (fgets(line, sizeof (line)-1, fd)) {
  341.     char* cp = cp = strchr(line, '#');
  342.     if (cp || (cp = strchr(line, '\n')))
  343.         *cp = '\0';
  344.     /* trim off trailing white space */
  345.     for (cp = strchr(line, '\0'); cp > line; cp--)
  346.         if (!isspace(cp[-1]))
  347.         break;
  348.     *cp = '\0';
  349.     if (line[0] != '\0')
  350.         pats->append(new RegEx(line));
  351.     }
  352.     return (pats);
  353. }
  354.